""" 
    
    Text renderer for appuifw.Canvas.
    
"""

__author__ = "Mikko Ohtamaa <mikko@redinnovation.com"
__docformat__ = "epytext"
__copyright__ = "Red Innovation Ltd."
__license__ = "BSD"

class TextRenderer:
    """ Simple multi-line text rendering for PyS60 Canvas.
    
    TextRenderer remembers the cursor position, allowing you to
    sequentially add more text.
    
    Basic support for wrapping too long lines exists.
    
    Example::
    
        canvas = appuifw.Canvas()
        renderer = TextRenderer(canvas)
        renderer.set_position(50,50)
        renderer.render_string("Word 1")
        renderer.render_line("Word 2")
        renderer.render("Text split\nby new lines")       
        renderer.render("This is a very long text which is automatically wrapped")
    """
    
    def __init__(self, canvas):
        """ Construct text renderer.
        
        Inital cursor position is (0, 0). 
             
        @param canvas appuifw.Canvas instance 
        """
        
        # Used canvas
        self.canvas = canvas
        
        # Coordinates of the cursor
        self.coords = [0,0]
        
        self.spacing = 1
        
    def set_line_spacing(self, spacing):
        """ Set Y pixels between text lines.
        
        """
        self.spacing = spacing
                
    def set_position(self, coords):
        """ Set the position of the cursor.
        
        @param coords [X,Y] sequence
        """
        self.coords = coords
        
    def move_cursor(self, x, y):
        """ Set cursor position relative to the current coordinates.
        
        """
        self.coords[0] += x
        self.coords[1] += y
        
    def render_string(self, text, font, fill):
        """ Render a line and moves cursor right. """
        bounding, to_right, fits = self.canvas.measure_text(text, font=font)
        self.canvas.text([self.coords[0], self.coords[1] - bounding[1]], unicode(text), font=font, fill=fill)
        self.coords = [self.coords[0] + to_right, self.coords[1]]
        
    def render_line(self, text, font, fill):
        """ Render one line of text.
        
        Moves cursor below.
        
        @param line string
        """
            
        bounding, to_right, fits = self.canvas.measure_text(text, font=font)
        
        # canvas.text coordinates are the baseline position of the rendered
        # text. It's not top left position.
        self.canvas.text([self.coords[0], self.coords[1] - bounding[1]], unicode(text), font=font, fill=fill)
        
        # Move cursor one line below
        self.coords = [self.coords[0], 
                       self.coords[1] - bounding[1] + bounding[3] + self.spacing                       
                       ]

    def chop(self, text, font, width):
        """ Wrap text to lines. 
        
        @param text Row of text to wrap
        @param width pixels we can use for one line
        @param font appuifw font description
                
        TODO: Smarter breaker char logic.
        """
        
        lines = []
        
        # Paragraph yet to be chopped
        text_left = text

        while len(text_left) > 0: 
            bounding, to_right, fits = self.canvas.measure_text(
                    text_left, font=font, 
                    maxwidth=width, maxadvance=width)
            
            if fits <= 0:
                # TODO: 
                lines.append(text_left)
                break
                    
            #print "tor:" + str(to_right) + " fits:" + str(fits)
            slice = text_left[0:fits]
        
            # How many chars we can skip at the end of the row
            # (whitespaces at the end of the row)
            adjust = 0
        
            if len(slice) < len(text_left):
                # Use the last space as a break point
                rindex = slice.rfind(" ")            
                if rindex > 0:
                    adjust = 1
                    slice = slice[0:rindex]
                                
            lines.append(slice)
            text_left = text_left[len(slice)+adjust:]
        
        return lines
        
    def render(self, text, font=('normal', 14), fill=0x000000):
        """ Render a piece of text.
        
        Primitive text wrap support.
        
        Strings are automatically converted to unicode.
        
        @param text: Multiline text
        @param font: appuifw font description (optional)
        @param fill: appuifw fill description (optional)
        
        @type text: unicode or str
        @return None
        """
        text = unicode(text)        
        max_width = self.canvas.size[0] - self.coords[0]
        #print "Max width: " + str(max_width)
        lines = text.split("\n")
        for line in lines:                        
            chopped_lines = self.chop(line, font, max_width)
            for chopped_line in chopped_lines:
                self.render_line(chopped_line, font, fill)


                